package com.fstec.ks.master.netty;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.ConcurrentHashMap;

import com.sinotn.ks.definition.Computer;
import com.sinotn.ks.definition.Message;
import com.sinotn.ks.definition.MessageSendCallback;
import com.sinotn.ks.netty.message.SimpleMessage;

/**
 * 默认简单的客户端电脑实现类。提供{@link com.sinotn.ks.definition.Computer Computer}接口的默认实现。
 * @Title AbstractComputer.java
 * @Package com.sinotn.ks.definition.provider
 * @Description
 * Copyright: Copyright (c) 2015
 * Company:北京信诺软通
 *
 * @author <a href="mailto:xieqj@sinotn.com">谢启进</a>
 * @date 2016年11月12日 下午3:39:18
 * @version V1.0
 */
public class DefaultComputer implements Computer{
	//客户端电脑网络连接ID
	private String socketId;
	//客户端IP地址
	private String ipAddr="0.0.0.0";
	private int[] intIpAddr;
	//客户端程序识别码
	private int vendor=0;
	//客户端版本号
	private String version;
	//注册密钥
	private String regKey;
	//网络连接隧道
	private Channel channel;
	//动态属性集合
	private ConcurrentHashMap<String, Object> attribute=new ConcurrentHashMap<String, Object>();

	public DefaultComputer(){}

	public DefaultComputer(Channel channel){
		this.channel=channel;
		this.socketId=channel.id().asLongText();

		SocketAddress socketAddr=channel.remoteAddress();
		if((null!=socketAddr)&&(socketAddr instanceof InetSocketAddress)){
			InetSocketAddress inetSocket=(InetSocketAddress)socketAddr;
			InetAddress inetAddr=inetSocket.getAddress();
			if(null!=inetAddr){
				this.ipAddr=inetAddr.getHostAddress();
			}
		}
	}
	
	public void updateSession(){
		this.getChannel().attr(MessageHandler.SESSION_KEY).set(this);
	}

	public DefaultComputer(DefaultComputer computer){
		this.channel=computer.channel;
		this.socketId=computer.socketId;
		this.ipAddr=computer.ipAddr;
		this.vendor=computer.vendor;
		this.version=computer.version;
		this.regKey=computer.regKey;
		if(computer.attribute.size()>0){
			this.attribute.putAll(computer.attribute);
		}
	}


	public void setChannel(Channel channel) {
		this.channel = channel;
	}

	protected Channel getChannel() {
		return channel;
	}

	@Override
	public String getVersion() {
		return version;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	@Override
	public String getRegKey() {
		return regKey;
	}

	public void setRegKey(String regKey) {
		this.regKey = regKey;
	}

	public void setIpAddr(String ipAddr) {
		this.ipAddr = ipAddr;
	}

	public void setVendor(int vendor) {
		this.vendor = vendor;
	}

	/*
	 *
	 * @see com.sinotn.ks.definition.Computer#getSocketId()
	 */
	@Override
	public String getSocketId() {
		return this.socketId;
	}

	@Override
	public String getIpAddr() {
		return this.ipAddr;
	}

	@Override
	public int[] getIntIpAddr() {
		if(this.intIpAddr==null){
			String[] params=this.ipAddr.split("\\.");
			int len=params.length;
			int[] ints=new int[len];
			for(int i=0;i<len;i++){
				ints[i]=Integer.valueOf(params[i]);
			}
			this.intIpAddr=ints;
			return ints;
		}
		return this.intIpAddr;
	}

	@Override
	public void disconnect() {
		this.channel.close();
	}

	@Override
	public Object getAttribute(String key) {
		return this.attribute.get(key);
	}

	@Override
	public Object removeAttribute(String key) {
		if(key==null){
			this.attribute.clear();
			return null;
		}
		return this.attribute.remove(key);
	}

	@Override
	public void setAttribute(String key, Object value) {
		this.attribute.put(key, value);
	}

	@Override
	public void release() {
		this.attribute.clear();
	}

	@Override
	public int getVendor() {
		return this.vendor;
	}

	@Override
	public String toString() {
		StringBuilder sb=new StringBuilder();
		sb.append("{");
		sb.append("\"socketId\":\"").append(this.socketId).append("\"");
		sb.append(",\"ipAddr\":\"").append(this.ipAddr).append("\"");
		sb.append(",\"vendor\":").append(this.vendor);
		if(null!=this.regKey){
			sb.append(",\"regKey\":\"").append(this.regKey).append("\"");
		}
		if(null!=this.version){
			sb.append(",\"version\":\"").append(this.version).append("\"");
		}
		sb.append("}");
		return sb.toString();
	}

	@SuppressWarnings("unchecked")
	@Override
	public void sendMessage(Message msg) {
		if(msg!=null && this.channel!=null && this.channel.isActive()){
			ChannelFuture future=this.channel.writeAndFlush(msg);
			future.addListener(new DefaultListener());
		}
	}

	@Override
	public void sendMessage(Message msg, boolean sync) {
		if(null==msg && this.channel!=null && this.channel.isActive()) {
			return;
		}
		ChannelFuture future=this.channel.writeAndFlush(msg);
		if(sync){//同步阻塞
			future.awaitUninterruptibly();
			Throwable e=future.cause();
			if(e!=null){
				if(e instanceof RuntimeException){
					throw (RuntimeException)e;
				}else{
					throw new RuntimeException(e);
				}
			}
		}
	}

	@SuppressWarnings({"unchecked" })
	@Override
	public void sendMessage(Message msg,final MessageSendCallback msc) {
		if(null==msg && this.channel!=null && this.channel.isActive()){
			return;
		}
		ChannelFuture future=this.channel.writeAndFlush(msg);
		if(null==msc){
			future.addListener(new DefaultListener());
		}else{
			future.addListener(new WrapperListener(msc));
		}
	}

	@Override
	public void selfDiagnose(String reportId, String strategy) {
		StringBuilder sb=new StringBuilder();
		sb.append("{\"reportId\":\"").append(reportId).append("\"");
		sb.append(",\"strategy\":\"").append(strategy).append("\"");
		sb.append("}");
		SimpleMessage message=new SimpleMessage(ResponseMessageType.SELF_DIAGNOSE, 0);
		message.setText(sb.toString());
		this.sendMessage(message, true);
	}
}
